package codingInterview.leetcode.editor.cn;

//请实现一个函数用来判断字符串是否表示数值（包括整数和小数）。 
//
// 数值（按顺序）可以分成以下几个部分： 
//
// 
// 若干空格 
// 一个 小数 或者 整数 
// （可选）一个 'e' 或 'E' ，后面跟着一个 整数 
// 若干空格 
// 
//
// 小数（按顺序）可以分成以下几个部分： 
//
// 
// （可选）一个符号字符（'+' 或 '-'） 
// 下述格式之一：
// 
// 至少一位数字，后面跟着一个点 '.' 
// 至少一位数字，后面跟着一个点 '.' ，后面再跟着至少一位数字 
// 一个点 '.' ，后面跟着至少一位数字 
// 
// 
// 
//
// 整数（按顺序）可以分成以下几个部分： 
//
// 
// （可选）一个符号字符（'+' 或 '-'） 
// 至少一位数字 
// 
//
// 部分数值列举如下： 
//
// 
// ["+100", "5e2", "-123", "3.1416", "-1E-16", "0123"] 
// 
//
// 部分非数值列举如下： 
//
// 
// ["12e", "1a3.14", "1.2.3", "+-5", "12e+5.4"] 
// 
//
// 
//
// 示例 1： 
//
// 
//输入：s = "0"
//输出：true
// 
//
// 示例 2： 
//
// 
//输入：s = "e"
//输出：false
// 
//
// 示例 3： 
//
// 
//输入：s = "."
//输出：false 
//
// 示例 4： 
//
// 
//输入：s = "    .1  "
//输出：true
// 
//
// 
//
// 提示： 
//
// 
// 1 <= s.length <= 20 
// s 仅含英文字母（大写和小写），数字（0-9），加号 '+' ，减号 '-' ，空格 ' ' 或者点 '.' 。 
// 
// Related Topics 字符串 👍 303 👎 0

import java.util.Arrays;

//Java：剑指 Offer 20 - 表示数值的字符串
public class BiaoShiShuZhiDeZiFuChuanLcof {
    public static void main(String[] args) {
        Solution solution = new BiaoShiShuZhiDeZiFuChuanLcof().new Solution();
        // TO TEST
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        String str;
        int index;

        public boolean isNumber(String s) {
            if (s.length() == 0) return false;
            this.str = s.trim(); //去掉首尾空格
            index = 0;
            boolean isNum = scanInteger();
            System.out.println(isNum);
            if (index < str.length() && str.charAt(index) == '.') {
                index++;
                // 使用|| 是因为 '.'前后只要其中一个方向有数字就可以
                isNum = scanUnsignedInteger() || isNum;
            }
            System.out.println(isNum);
            if (index < str.length() && (str.charAt(index) == 'e' || str.charAt(index) == 'E')) {
                index++;
                // 使用 && 是因为 'e/E' 前后都必须有数字
                isNum = scanInteger() && isNum;
            }
            System.out.println(isNum);
            return isNum && index==str.length(); //如果一切正常，那么指针能够到最后，未到最后说明中间有异常字符
        }

        boolean scanInteger() {
            if (index < str.length() && (str.charAt(index) == '+' || str.charAt(index) == '-'))
                index++;
            return scanUnsignedInteger();
        }

        boolean scanUnsignedInteger() {
            int before = index;
            while (index < str.length() && str.charAt(index) >= '0' && str.charAt(index) <= '9') {
                index++;
            }
            return index > before; //判断是否有识别到数字
        }

    }

    //leetcode submit region end(Prohibit modification and deletion)
    public boolean isNumber(String s) {
        if (s.length() == 0) return false;
        boolean res = true;
        int[] state = new int[]{-1, -1, -1, -1}; // 依次为+-｜.｜eE｜数字
        s = s.trim(); // 去掉首尾空格
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (s.charAt(i) >= '0' && s.charAt(i) <= '9') { // 判断数字
                state[3] = i; // 离当前指针最近的数字下标
            } else if ((s.charAt(i) == '+' || s.charAt(i) == '-') && (i == 0 || i == state[2] + 1)) { //+/-出现时只可能在开头或e/E后一位
                state[0] = i;
            } else if (s.charAt(i) == '.' && state[1] < 0 && state[2] < 0) { //.只能一次,且出现时不能有e
                state[1] = i;
            } else if ((s.charAt(i) == 'e' || s.charAt(i) == 'E') && state[2] < 0 && state[3] >= 0 && state[3] < i) { // eE只能一次，且前后必须有数字
                state[2] = i;
            } else {
                return false;
            }
        }
        return state[3] > state[2]; //判断e/E后是否有数字
    }
}
